#include "TransformComponent.h"



void RTransformComponent::SetPosition(const SVec3 & InPosition)
{
    Position=InPosition;

    //更新局部坐标系下的位置
    if(!Parent)
    {
        LocalPosition=Position;
    }
    else
    {
        LocalPosition=Parent->GetWorldMatrix().Inverse().TransformPosition(Position);
    }

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentPositionChanged();
    }
}

void RTransformComponent::SetRotation(const SQuat &InRotation)
{
    Rotation=InRotation;
    Forward= Rotation.GetForwardDirection();
    Up= Rotation.GetUpDirection();
    Right= Rotation.GetRightDirection(); 
    EulerAngleInDegree=CMath::RadianToDegree(Rotation.ToEuler());


    //更新局部坐标系下的旋转
    if(!Parent)
    {
        LocalRotation=Rotation;
    }
    else
    {
        LocalRotation=
            Parent->Rotation.Inverse()*Rotation;
        
        LocalEulerAngleInDegree=CMath::RadianToDegree(LocalRotation.ToEuler());
    }

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentRotationChanged();
    }
}

void RTransformComponent::SetEulerAngleInDegree(const SVec3 &InEulerAngleInDegree)
{
    EulerAngleInDegree=InEulerAngleInDegree;
    Rotation=SQuat::FromEuler(CMath::DegreeToRadian(EulerAngleInDegree));
    Forward= Rotation.GetForwardDirection();
    Up= Rotation.GetUpDirection();
    Right= Rotation.GetRightDirection();

    //更新局部坐标系下的旋转
    if(!Parent)
    {
        LocalRotation=Rotation;
    }
    else
    {
        LocalRotation=
            Parent->Rotation.Inverse()*Rotation;

        LocalEulerAngleInDegree=CMath::RadianToDegree(LocalRotation.ToEuler());
    }
}

void RTransformComponent::SetScale(const SVec3 &InScale)
{
    Scale=InScale;

    //更新局部坐标系下的缩放
    if(!Parent)
    {
        LocalScale=Scale;
    }
    else
    {
        LocalScale=SVec3::SafeDivide(Scale,Parent->Scale);
    }

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentScaleChanged();
    }
}

void RTransformComponent::SetParent(TSharedObjectPtr<RTransformComponent> InParent, bool bKeepWorldPosRotationScale)
{
    InParent->AddChild(this,bKeepWorldPosRotationScale);
}

void RTransformComponent::AddChild(TSharedObjectPtr<RTransformComponent> InChild, bool bKeepWorldPosRotationScale)
{
    if(InChild->Parent)
    {
        InChild->Parent->RemoveChild(InChild);
    }

    InChild->Parent=this;
    Children.Add(InChild);
    InChild->IndexInParent=Children.Num()-1;

    if(bKeepWorldPosRotationScale)
    {
        InChild->LocalPosition= GetWorldMatrix().Inverse().TransformPosition(InChild->Position);
        InChild->LocalRotation=Rotation.Inverse()*InChild->Rotation;
        InChild->LocalEulerAngleInDegree=CMath::RadianToDegree(InChild->LocalRotation.ToEuler());
        InChild->LocalScale=SVec3::SafeDivide(InChild->Scale,Scale);
    }
    else
    {
        InChild->Position=GetWorldMatrix().TransformPosition(InChild->LocalPosition);
        InChild->Rotation=Rotation*InChild->LocalRotation;
        InChild->Forward= InChild->Rotation.GetForwardDirection();
        InChild->Up= InChild->Rotation.GetUpDirection();
        InChild->Right= InChild->Rotation.GetRightDirection();
        InChild->EulerAngleInDegree=CMath::RadianToDegree(InChild->Rotation.ToEuler());
        InChild->Scale=Scale*InChild->LocalScale;
    }
}

void RTransformComponent::RemoveChild(TSharedObjectPtr<RTransformComponent> InChild)
{
    if(InChild->Parent!=this)
    {
        return;
    }

    InChild->Parent=nullptr;
    Children.RemoveAt(InChild->IndexInParent);
    InChild->IndexInParent=-1;
}

SMatrix4x4 RTransformComponent::GetWorldMatrix() const
{
    return SMatrix4x4( 
        Position
        ,Rotation
        ,Scale);
}

void RTransformComponent::PostParentPositionChanged()
{
    Position= Parent->GetWorldMatrix().TransformPosition(LocalPosition);

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentPositionChanged();
    }
}

void RTransformComponent::PostParentRotationChanged()
{
    Rotation= Parent->Rotation*LocalRotation;
    EulerAngleInDegree=CMath::RadianToDegree(Rotation.ToEuler());
    Forward= Rotation.GetForwardDirection();
    Up= Rotation.GetUpDirection();
    Right= Rotation.GetRightDirection();

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentRotationChanged();
    }
}

void RTransformComponent::PostParentScaleChanged()
{
    Scale= Parent->Scale*LocalScale;

    //更新子节点的位姿
    for(auto& Child: Children)
    {
        Child->PostParentScaleChanged();
    }
}
